/*
 * repeatAnalyser.cc
 *
 *  Created on: Apr 17, 2013
 *      Author: hxin
 */

#include "RepeatAnalyser.h"
#include <cstdlib>
#include <algorithm>
#include "common.h"

RepeatAnalyser::RepeatAnalyser() {
	repeatMark = NULL;
	tandemMark = NULL;
	validMark = NULL;
}

RepeatAnalyser::~RepeatAnalyser() {
	if (repeatMark != NULL) {
		delete[] repeatMark;
		repeatMark = NULL;
	}
	if (tandemMark != NULL) {
		delete[] tandemMark;
		tandemMark = NULL;
	}
	if (validMark != NULL) {
		delete[] validMark;
		validMark = NULL;
	}
}

void RepeatAnalyser::loadHashFile(string hashName) {
	ht.loadHash(hashName);
}

void RepeatAnalyser::loadRefFile(string refName) {
	if (refFile.is_open()) {
		refFile.close();
		refPos.clear();
	}

	refFile.open(refName.c_str());
	string refMetaName = "." + refName + ".meta";
	fstream refMetaFile(refMetaName.c_str(), ios_base::in);

	if (refMetaFile.is_open() ) {
		unsigned long int tempPos;
		while (refMetaFile.good()) {
			refMetaFile >> tempPos;
			refPos.push_back( (streampos)tempPos);
		}

	} else {

		refMetaFile.open(refMetaName.c_str(), ios_base::out|ios_base::trunc);

		string temp;

		while (refFile.good()) {
			getline(refFile, temp);
			if (temp[0] == '>') {
				refPos.push_back(refFile.tellg());
				refMetaFile << (unsigned long int) refFile.tellg() << endl;
			}
		}
	}

	refMetaFile.close();
}

bool RepeatAnalyser::loadChromo(int chromoNum) {

	cout << "loading chromosome: " << chromoNum << endl;

	if (chromoNum >= refPos.size())
		return false;

	ht.loadChromo(chromoNum);

	chromosome.clear();
	refFile.clear();
	refFile.seekg(refPos[chromoNum]);

	string temp;

	while (refFile.good() && (temp.size() == 0 || temp[0] != '<')) {
		chromosome.append(temp);
		getline(refFile, temp);
//		cout << temp[0] << endl;
		if (temp[0] == '>') {
			cout << "stop!" << endl;
			break;
		}
	}

//	cout << chromosome << endl;
	return true;
}

void RepeatAnalyser::markRepeat(int threshold) {
	if (repeatMark != NULL) {
		delete[] repeatMark;
		repeatMark = NULL;
	}
	if (validMark != NULL) {
		delete[] validMark;
		validMark = NULL;
	}

	ofstream repeatFile ("repeatFile");
	repeatFile << chromosome.size();

	repeatMark = new bool[chromosome.size()]();
	validMark = new bool[chromosome.size()]();

	string kmer;

	for (unsigned int i = 0; i <= chromosome.size() - ht.getKmerLength(); i++) {
		kmer = chromosome.substr(i, ht.getKmerLength());

		if (kmer.find('N') != string::npos || kmer.find('M') != string::npos
				|| kmer.find('R') != string::npos) {
//			cout << "0";
			repeatFile << 0 << " ";
			continue;
		}

		repeatFile << ht.getLocLength(kmer) << " ";
		validMark[i] = true;

		if (ht.getLocLength(kmer) >= threshold) //{
			repeatMark[i] = true;
//			cout << "1";
//		} else
//			cout << "0";

	}

	repeatFile.close();
//	cout << endl;

}

void RepeatAnalyser::markTandemRepeat(int errorAllowed) {
	cout << "MarkTandemRepeat!" << endl;

	if (tandemMark != NULL) {
		delete[] tandemMark;
		tandemMark = NULL;
	}

	tandemMark = new bool[chromosome.size()];

	string kmer;
	int error_count = 0;
	unsigned int repeatInterval = 0;

	unsigned int chromoEnd = chromosome.size() - ht.getKmerLength();

	for (int i = 0; i <= chromoEnd; i++) {
		makeProgress("Marking tandem", i, (int) chromosome.size(), 1000);

		if (repeatMark[i]) {
			kmer = chromosome.substr(i, ht.getKmerLength());
			ht.queryKmer(kmer);
			ht.setLocPos(i);
			if (ht.endLoc()) {
//				cout << "EndLoc" << endl;
				continue;
			}

			repeatInterval = ht.getLoc() - i;
//			cout << "repeatInterval: " << repeatInterval << endl;

			if (repeatInterval < ht.getKmerLength()) {
				for (int j = i; j < i + repeatInterval + ht.getKmerLength();
						j++)
					tandemMark[j] = true;
				continue;
			}

			error_count = 0;

			int repeat_beg = i;

//			cout << "repeat_beg: " << repeat_beg << endl;

			int front_bound = max(0,
					i - (int) repeatInterval + (int) ht.getKmerLength());

			for (int j = i - 1; j >= front_bound; j--) {

				if (validMark[j]) {
					kmer = chromosome.substr(j, ht.getKmerLength());

					if (ht.searchLoc(kmer, j + repeatInterval, errorAllowed)) {
						repeat_beg = j;
					} else {
						error_count++;
						if (error_count > errorAllowed)
							break;
					}
				}
			}

			int repeat_end = repeat_beg + repeatInterval - ht.getKmerLength();
//			cout << "repeat_beg: " << repeat_beg << " repeat_end: "
//					<< repeat_end << endl;

			error_count = 0;

			for (int j = repeat_beg; j <= repeat_end; j++) {

//				cout << "j: " << j << endl;

				if (validMark[j]) {

					kmer = chromosome.substr(j, ht.getKmerLength());

//					cout << "kmer: " << kmer << endl;

					if (!ht.searchLoc(kmer, j + repeatInterval, errorAllowed)) {
//						cout << "j+repeatInterval: " << j + repeatInterval
//								<< endl;
//						cout << "fail!" << endl;
						error_count++;
					}
				} else
					error_count++;

				if (error_count > errorAllowed)
					break;
			}

			//If there are really less
			if (error_count <= errorAllowed) {
				for (int j = repeat_beg;
						j < repeat_end + ht.getKmerLength() + repeatInterval;
						j++)
					tandemMark[j] = true;
			}

		}

	}

	for (int i = 0; i < chromosome.size(); i++) {
		cout << (int) tandemMark[i];
		if (i % 80 == 79)
			cout << endl;
	}
	cout << endl;
}
